<script lang="ts">
    import { Input } from "../Input";
    import { Select } from "../Select";
    import { useClassList } from "../utils/useClassList";
    import PageItem from "./PageItem.svelte";
    import PageNext from "./PageNext.svelte";
    import PagePrev from "./PagePrev.svelte";
    import type { PaginationProps } from "./Pagination";
    import { _ } from "svelte-i18n";

    const pages = $derived([
        { value: 10, label: "10 " + $_("Pagination.page") },
        { value: 20, label: "20 " + $_("Pagination.page") },
        { value: 50, label: "50 " + $_("Pagination.page") },
        { value: 100, label: "100 " + $_("Pagination.page") },
    ]);

    let { current = $bindable(1), ...props }: PaginationProps = $props();

    const classList = $derived(
        useClassList(props, "cm-pagination", {
            [`cm-pagination-${props.shape}`]: props.shape,
            [`cm-pagination-${props.size}`]: props.size,
        })
    );

    const total = $derived(props.total ?? 0);
    let pageSize = $derived(props.pageSize ?? 10);

    const PAGE_SHOW_MAX = 7;
    const REST_PAGE_MAX_SIZE = 5;
    const showNums = props.showNums ?? true;
    const showTotal = props.showTotal ?? true;
    const ps = $derived(props.pages ?? pages);

    const showJumper = props.showJumper ?? true;
    const showPage = props.showPage ?? true;

    const prev = () => {
        if (current > 1) {
            handleChange(current - 1);
        }
    };

    const next = () => {
        if (current < calcPage()) {
            handleChange(current + 1);
        }
    };

    const gotoPage = (v: string) => {
        handleChange(parseInt(v, 10));
    };

    const calcPage = () => {
        // 没数据的时候默认为第一页
        if (total === 0) {
            return 1;
        }
        return Math.floor((total - 1) / pageSize) + 1;
    };

    const isValid = (page: number) => {
        return typeof page === "number" && page >= 1;
    };

    /**
     * 页号改变
     * @method _handleChange
     * @param p 当前页号
     * @returns {*}
     * @private
     */
    const handleChange = (p: number) => {
        let page = p;
        if (isValid(page) && page !== current) {
            if (page > calcPage()) {
                page = calcPage();
            }

            current = page;
            props.onchange?.(page, pageSize);
        }
    };

    const onChangePageSize = (size: number) => {
        const totalPages = Math.floor((total - 1) / size) + 1;
        props.onchangepagesize?.(size);
        if (current > totalPages) {
            current = 1;
            props.onchange?.(1, pageSize);
        }
    };

    function getPageNumbers() {
        let pageList = [];
        let restLeftPageList: number[] = []; // pages before ...
        let restRightPageList: number[] = []; // pages after ...
        /** Pager truncation logic (t is the total number of pages, c is the current page):
            - No need to truncate when t<=7 pages
            - When t>7
                - When c<4, the fourth is a truncation symbol (...)
                - When c=4, the sixth is the truncation symbol (...)
                - When 4<c<t-3, the second and sixth are truncation symbols (...)
                - When t-3<=c<=t, the second is the truncation symbol (...), followed by the 5th from the bottom-the 1st from the bottom
            Truncation character + number, the total number is 7

            分页器截断逻辑（t为总页数，c为当前页）：
            - t<=7 页的时候不需要截断
            - 当 t>7 时
                - 当 c<4 时，第4个为截断符号（...）
                - 当 c=4 时，第6个为截断符号（...）
                - 当 4<c<t-3 时，第2个与第6个为截断符号（...）
                - 当 t-3<=c<=t 时，第 2 个为截断符号（...），后面为倒数第5个-倒数第1个
            截断符+数字 总共个数为7个
        */
        const totalPageNum = calcPage();
        if (totalPageNum <= PAGE_SHOW_MAX) {
            pageList = Array.from({ length: totalPageNum }, (v, i) => i + 1);
            restLeftPageList = [];
            restRightPageList = [];
        } else {
            switch (true) {
                case current < 4:
                    pageList = [1, 2, 3, 4, "•••", totalPageNum - 1, totalPageNum];
                    restRightPageList = Array.from({ length: Math.min(totalPageNum - 6, REST_PAGE_MAX_SIZE) }, (v, i) => i + 5);
                    restLeftPageList = [];
                    break;
                case current === 4:
                    pageList = [1, 2, 3, 4, 5, "•••", totalPageNum];
                    restRightPageList = Array.from({ length: Math.min(totalPageNum - 6, REST_PAGE_MAX_SIZE) }, (v, i) => i + 6);
                    restLeftPageList = [];
                    break;
                case 4 < current && current < totalPageNum - 3: {
                    const middleNumbers = Array.from({ length: 3 }, (v, i) => current + (i - 1));
                    pageList = ([1] as any[]).concat("•••", middleNumbers, "•••", totalPageNum);
                    // length: total-(currentPage+1)-1
                    restRightPageList = Array.from({ length: Math.min(totalPageNum - current - 2, REST_PAGE_MAX_SIZE) }, (v, i) => current + i + 2);
                    restLeftPageList = Array.from({ length: Math.min(current - 3, REST_PAGE_MAX_SIZE) }, (v, i) => i + 2);
                    break;
                }
                case current - 3 <= current && current <= totalPageNum: {
                    const right = Array.from({ length: 5 }, (v, i) => totalPageNum - (4 - i));
                    pageList = [1, "•••" as const].concat(right);
                    restRightPageList = [];
                    restLeftPageList = Array.from({ length: Math.min(right[0] - 2, REST_PAGE_MAX_SIZE) }, (v, i) => i + 2);
                    break;
                }
                default:
                    break;
            }
        }
        return { pageList, restLeftPageList, restRightPageList };
    }
</script>

{#snippet rednderItems()}
    {#if showNums}
        {@const pageNumbers = getPageNumbers()}
        {#each pageNumbers.pageList as number}
            {@const active = current === number}
            <PageItem {active} onclick={handleChange.bind(null, number)} currentIndex={number} />
        {/each}
    {/if}
{/snippet}
<div class={classList} style={props.style}>
    {#if props.mini}
        <ul class="cm-pagination-num-list">
            <PagePrev {current} onclick={prev} />
            <Input style={`width: ${props.size === "small" ? "35px" : "50px"}`} bind:value={current} size={props.size} onchange={gotoPage} />
            <span class="cm-pagination-mini-pages">/ {calcPage()}</span>
            <PageNext {current} onclick={next} disabled={current === calcPage()} />
        </ul>
    {:else}
        {#if showTotal}
            <span class="cm-pagination-text">{$_("Pagination.total")}{total}{$_("Pagination.item")}</span>
        {/if}
        <div class="cm-pagination-right">
            <ul class="cm-pagination-num-list">
                <PagePrev {current} onClick={prev} />
                {@render rednderItems()}
                <PageNext {current} onClick={next} disabled={current === calcPage()} />
            </ul>
            {#if showPage}
                <span class="cm-pagination-sizer">
                    <Select value={pageSize} size={props.size} onchange={onChangePageSize} data={ps}></Select>
                </span>
            {/if}
            {#if showJumper}
                <span class="cm-pagination-jumper">
                    <span class="cm-pagination-text">{$_("Pagination.jump")}</span>
                    <Input style={`width: ${props.size === "small" ? "35px" : "50px"}`} bind:value={current} size={props.size} onchange={gotoPage} />
                    <span class="cm-pagination-text">{$_("Pagination.unit")}</span>
                </span>
            {/if}
        </div>
    {/if}
</div>
